﻿using cn.school.api;
using cn.school.api.v1;
using cn.school.Restful.Filter;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;

namespace cn.school.Restful;

public class RestfulService
{
    private readonly WebApplicationBuilder _builder;
    private WebApplication? _application;
    private readonly IConfiguration _configuration;
    private readonly IServiceCollection _services;
    private readonly IWebHostEnvironment _env;

    public RestfulService(string[] args)
    {
        _builder = WebApplication.CreateBuilder(args);
        _configuration = _builder.Configuration;
        _services = _builder.Services;
        _env = _builder.Environment;
    }

    public RestfulService Configure()
    {
        ConfigureServices();
        _application = _builder.Build();
        ConfigureApplication();
        return this;
    }

    public void Run()
    {
        _application?.Run();
    }

    private void ConfigureServices()
    {
        _services.AddControllers(options => options.Filters.Add<ExceptionFilter>());
        _services.AddEndpointsApiExplorer();

        _services.AddPooledDbContextFactory<ManageContext>(
            opts => opts.UseNpgsql(_configuration.GetConnectionString("Postgres"))
            .UseSnakeCaseNamingConvention()
            .UseLoggerFactory(LoggerFactory.Create(builder => { builder.AddConsole(); })), 100
            );
        _services.AddScoped<ManageContextFactory>();
        _services.AddScoped(sp => sp.GetRequiredService<ManageContextFactory>().CreateDbContext());
        AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
        AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);

        _services.AddScoped<IStudentManage, StudentManage>();

        _services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = _configuration["application:name"],
                Description = _configuration["application:description"],
                Version = _configuration["application:version"]
            });
        });
    }

    private void ConfigureApplication()
    {
        if (_application is null)
            throw new InvalidOperationException();

        if (_env.IsDevelopment())
        {
            _application.UseSwagger();
            _application.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint(_configuration["application:swagger:path"], $"{_configuration["application:swagger:description"]} {_configuration["application:version"]}");
            });
            _application.UseDeveloperExceptionPage();
        }
        _application.UseAuthorization();
        _application.MapControllers();
    }
}